﻿using System.IO;
using MvcSmartTool.Common;
using MvcSmartTool.WebGenerator.Views;
using MvcSmartTool.WebGenerator.Infrastructure.Grid.Interfaces;
using MvcSmartTool.WebGenerator.Infrastructure.Grid.Concretes;
using MvcSmartTool.WebGenerator.Infrastructure.Grid;
using MvcSmartTool.WebGenerator.App_Start;
using System;
using MvcSmartTool.WebGenerator.Models;
using MvcSmartTool.WebGenerator.Utils;
using MvcSmartTool.WebGenerator.Themes.Standard.Shared;
using MvcSmartTool.WebGenerator.Mappings;


namespace MvcSmartTool.WebGenerator {
    public class WebProjectWriter : BaseProjectWriter {
        public string Theme { get; set; }
        private static Guid s_projectGuid;
        public WebProjectWriter(string solutionName)
            : base(solutionName){
            Theme = "Standard";
        }
        public WebProjectWriter(string projectName, string projectOutput)
            : base(projectName) {
            OutputPath = projectOutput;
            Theme = "Standard";
        }
        public override string ProjectName {
            get { return SolutionName + ".WebMvc"; }
        }

        public static Guid ProjectGuid {
            get {
                if (s_projectGuid == Guid.Empty) {
                    s_projectGuid = Guid.NewGuid();
                }
                return s_projectGuid;
            }
        }
        protected override void InternalGenerate() {
            
            GenerateApp_Start();
            GenerateControllers();
            GenerateViewModels();
            GenerateModelScripts();
            GenerateViews();
            GenerateMappings();
            GenerateGrids();
            GenerateConfigs();
            CopyInfrastruresTemplate();
            GenerateHelpers();
            //TODO: Generate mores things I will think later
            GenerateProjectFile();
            FileWriterHelper.DirectoryCopy(Path.Combine("./assets"), Path.Combine(ProjectPath, "assets"), true);
            FileWriterHelper.DirectoryCopy(Path.Combine("./assets"), Path.Combine(ProjectPath, "assets"), true);
        }

        private void GenerateHelpers(){
            var mvcHelper = new MvcHelpers(){
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(Path.Combine(ProjectPath, "Utils"), "MvcHelpers.cs", mvcHelper.TransformText());

            var gridIds = new GridIdConstants(){
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(Path.Combine(ProjectPath, "Utils"), "GridIdConstants.cs", gridIds.TransformText());
            
            var gridInfo = new GridInfo() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(Path.Combine(ProjectPath, "Utils"), "GridInfo.cs", gridInfo.TransformText());
        }

        private void GenerateConfigs() {
            //Generate Assembly Info
            var ass = new AssemblyInfoTemplate {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(Path.Combine(ProjectPath,"Properties"), "AssemblyInfo.cs", ass.TransformText());
            // Generate Global.asax
            var global1 = new GlobalAsax() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, "Global.asax", global1.TransformText());
            var global = new GlobalAsaxTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, "Global.asax.cs", global.TransformText());
            var webConfig = new WebConfigTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, "Web.config", webConfig.TransformText());
            var webDebug = new WebDebugTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, "Web.Debug.config", webDebug.TransformText());
            var webRelease = new WebReleaseTemplate {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, "Web.Release.config", webRelease.TransformText());
        }

        private void GenerateApp_Start() {
            var directory = Path.Combine(ProjectPath, "App_Start");
            
            // Bundle Config
            var bundle = new BundleConfigTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(directory, "BundleConfig.cs", bundle.TransformText());

            // Filter Config
            var filter = new FilterConfigTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(directory, "FilterConfig.cs", filter.TransformText());

            // NInjectWeb Common file
            var ninject = new NInjectWebCommonTemplate() {
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(directory, "NInjectWebCommon.cs", ninject.TransformText());

            // Route Config
            var route = new RouteConfigTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(directory, "RouteConfig.cs", route.TransformText());

            // Web api Config
            var webApi = new WebApiConfigTemplate() {
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(directory, "WebApiConfig.cs", webApi.TransformText());
        }
        #region Private methods
        private void GenerateControllers() {
            var directory = Path.Combine(ProjectPath, "Controllers");

            //Copy BaseController Template
            CopyTemplate("BaseController", directory, SolutionName);
            CopyTemplate("HomeController", directory, SolutionName);
            CopyTemplate("AccountController", directory, SolutionName);
            CopyTemplate("GridController", directory, SolutionName);
            CopyTemplate("ErrorController", directory, SolutionName);
            foreach (var model in Models) {
                var modelTemplate = new ControllerTemplate() {
                    Model = model,
                    SolutionName = SolutionName
                };
                FileWriterHelper.WriteFile(directory, model.Name + "Controller.cs", modelTemplate.TransformText());
            }
        }
        private void CopyInfrastruresTemplate() {
            // 
            //Copy Lazy (In this function we didn't copy grid template.)
            // 
             var lazy = Path.Combine(ProjectPath, "Infrastructure/Lazy");
            FileWriterHelper.EnsurePath(lazy);
            CopyTemplate("ILazyLoader",lazy, SolutionName);
            CopyTemplate("LazyLoader", lazy, SolutionName);

            var infras = Path.Combine(ProjectPath,"Infrastructure");
            CopyTemplate("NewtonJsonResult", infras, SolutionName);
            
            //Filters
            var filters = Path.Combine(infras, "Filters");
            CopyTemplate("CustomHandleErrorAttribute", filters, SolutionName);
            CopyTemplate("AuthorizeAttribute", filters, SolutionName);
        }
        private void GenerateViewModels() {
            var directory = Path.Combine(ProjectPath, "Models");
            CopyTemplate("GridDataModel", directory, SolutionName);
            CopyTemplate("UserModel.txt","UserModel.cs",Path.Combine("./BaseTemplates/ViewModels"), directory, SolutionName);
            foreach (var model in Models) {
                var template = new ViewModelTemplate() {
                    SolutionName = SolutionName,
                    Model = model
                };
                FileWriterHelper.WriteFile(directory, model.Name + "ViewModel.cs", template.TransformText());
            }
        }
        /// <summary>
        /// Generate model script for knock out
        /// </summary>
        private void GenerateModelScripts(){
            var dict = Path.Combine(ProjectPath, "assets/js/models");
            foreach (var model in Models){
                var template = new ClientModelTemplate() {
                    SolutionName = SolutionName,
                    Model = model
                };
                FileWriterHelper.WriteFile(dict, model.Name.ToCamelCase() + "ViewModel.js", template.TransformText());
            }
           
        }
        /// <summary>
        /// Generate main view (grid) and CRUD for each model
        /// </summary>
        private void GenerateViews() {
            var directory = Path.Combine(ProjectPath, "Views");
            //Copy template view
            CopyTemplate("_Layout.cshtml.txt", "_Layout.cshtml", Path.Combine("./Themes", Theme,"Shared"), Path.Combine(directory,"Shared"), SolutionName);
            CopyTemplate("Error.cshtml.txt", "Error.cshtml", Path.Combine("./Themes", Theme, "Shared"), Path.Combine(directory, "Shared"), SolutionName);
            CopyTemplate("_Footer.cshtml.txt", "_Footer.cshtml", Path.Combine("./Themes", Theme, "Shared"), Path.Combine(directory, "Shared"), SolutionName);
            CopyTemplate("_Menu.cshtml.txt", "_Menu.cshtml", Path.Combine("./Themes", Theme, "Shared"), Path.Combine(directory, "Shared"), SolutionName);
            //CopyTemplate("_NavigationBar.cshtml.txt", "_NavigationBar.cshtml", Path.Combine("./Themes", Theme, "Shared"), Path.Combine(directory, "Shared"), SolutionName);
            CopyTemplate("ViewStart.cshtml.txt", "_ViewStart.cshtml", Path.Combine("./Themes", Theme,"Shared"), directory, SolutionName);
            CopyTemplate("Login.cshtml.txt", "Login.cshtml", Path.Combine("./Themes", Theme, "Account"), Path.Combine(directory, "Account"), SolutionName);
            CopyTemplate("Index.cshtml.txt", "Index.cshtml", Path.Combine("./Themes", Theme, "Home"), Path.Combine(directory, "Home"), SolutionName);
            var navigationBar = new NavigationBarTemplate() {
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(Path.Combine(directory, "Shared"), "_NavigationBar.cshtml", navigationBar.TransformText());
            //
            
            FileWriterHelper.EnsurePath(directory);
            foreach (var model in Models) {
                var indexView = new IndexViewTemplate() {
                    Model = model,
                    SolutionName = SolutionName
                };
                var editView = new EditViewTemplate() {
                    Model = model,
                    SolutionName = SolutionName
                };
                FileWriterHelper.WriteFile(Path.Combine(directory, model.Name), "Index.cshtml", indexView.TransformText());
                FileWriterHelper.WriteFile(Path.Combine(directory, model.Name), "_Create.cshtml", editView.TransformText());
            }

            // Generate View/Web.config
            var config = new WebConfig() {
                SolutionName = SolutionName
            };

            FileWriterHelper.WriteFile(directory, "Web.config", config.TransformText());
        }

        /// <summary>
        /// Generate mappings converter for view model <--> domain model
        /// </summary>
        private void GenerateMappings() {
            var directory = Path.Combine(ProjectPath, "Mappings");
            var template = new MappingTemplate() {
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(directory, "MappingDataProvider.cs", template.TransformText());
        }
        /// <summary>
        /// Generate grid for all models
        /// </summary>
        private void GenerateGrids() {
            var directory = Path.Combine(ProjectPath, "Infrastructure/Grid");
            FileWriterHelper.EnsurePath(directory);

            CopyTemplate("BaseGrid", Path.Combine(directory, "Concretes"), SolutionName);
            CopyTemplate("IGrid", Path.Combine(directory, "Interfaces"), SolutionName);
            //Generate GridProvider
            var provider = new GridDataProviderTemplate() {
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(directory, "GridDataProvider.cs", provider.TransformText());
            
            //Generate GridColumnDataProvider
            var cProvider = new GridColumnsProvider() {
                SolutionName = SolutionName,
                Model = Models
            };
            FileWriterHelper.WriteFile(directory, "GridColumnsProvider.cs", cProvider.TransformText());

            // Generate GridType enum
            var gType = new GridTypeTemplate() {
                Model = Models,
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(directory, "GridType.cs", gType.TransformText());

            // Generate Grid interface and implemented of it
            foreach (var model in Models) {
                var igrid = new GridInterfaceTemplate() {
                    SolutionName = SolutionName,
                    Model = model
                };
                var cgrid = new GridConcreteTemplate() {
                    SolutionName = SolutionName,
                    Model = model
                };
                FileWriterHelper.WriteFile(Path.Combine(directory, "Interfaces"), "I" + model.Name + "Grid.cs", igrid.TransformText());
                FileWriterHelper.WriteFile(Path.Combine(directory, "Concretes"), model.Name + "Grid.cs", cgrid.TransformText());
            }
        }
        private void GenerateProjectFile() {
            var template = new WebProjectTemplate() {
                Model = Models,
                SolutionName = SolutionName
            };
            FileWriterHelper.WriteFile(ProjectPath, ProjectName + ".csproj", template.TransformText());
        }
        #endregion
    }
}
